package pATT.bNEdit.learning;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;

import pATT.bNEdit.base.RedBayes;
@SuppressWarnings("unchecked")
public abstract class AlgoritmoAprendizajeEstructural {
/**
*Constructor
*/
 public AlgoritmoAprendizajeEstructural() {
    Variables= new Vector();
    Padres=new Vector();
    estados=new Vector();
    Datos=new Vector();
  }
  /**
  *Carga los tokens separados por "," en el vector destino
  *a partir de la cadena cadena
  */
 private void cargarTokens(Vector destino, String cadena){
        StringTokenizer tokens = new StringTokenizer(cadena, ",");
        while(tokens.hasMoreTokens()){
            String cad= tokens.nextToken();
            destino.addElement(new String(cad));
        }
  }

  /**
  *Verifica si un vector pertenece a un conjunto de vectores
  */
  protected boolean pertenece(Vector elem, Vector conj){
        for(int i=0; i<conj.size(); i++)
            if(igual(elem, (Vector)conj.get(i)))
                return true;
        return false;
  }
  /**
  *Verifica si un elemento pertenece al vector conj
  */
  private boolean pertenece(String elemento, Vector conj){
        for(int i=0; i<conj.size(); i++){
            String e=(String)conj.get(i);
            if(e.equals(elemento)) return true;
        }
        return false;
  }

  /**
  *Verifica si un vector es igual a otro
  */
  protected boolean igual(Vector v1, Vector v2){
        if(v1.size()!=v2.size()) return false;
        for(int i=0; i<v1.size(); i++){
            if(!((String)v1.get(i)).equals((String)v2.get(i)))
                return false;
        }
        return true;
  }
  /**
  *Carga los estados correspondientes en el vector estados
  *a partir de los datos cargados en Datos
  */
  private void cargarEstados(){
        Vector v=(Vector)Datos.get(0);
        for(int k=0; k<v.size(); k++){
            Vector estad= new Vector();
            estad.addElement((String)v.get(k));
            estados.addElement(estad);
        }

        for(int i=1; i<nroCasos; i++){
            v= (Vector)Datos.get(i);
            for(int j=0; j<v.size(); j++)
                if(!pertenece((String)v.get(j), (Vector)estados.get(j)))
                    ((Vector)estados.get(j)).addElement(v.get(j));
        }
  }

  /**
  *Obtiene el estado j-\uFFFDsimo de la instancia i-\uFFFDsima en Datos
  */
  protected String obtenerEstado(int i, int j){
        return (String)((Vector)Datos.get(i)).get(j);
  }

  /**
  *Obtiene los padres actuales de la variable i
  */
  protected Vector padres(int i){
        return (Vector)Padres.get(i);
  }

  /**
  *Carga las estructuras desde el archivo
  */
  protected void cargarDesdeArchivo(String nombreArch){
        try{
		Variables= new Vector();
                Padres=new Vector();
                estados=new Vector();
                Datos=new Vector();
        	FileReader fileReader= new FileReader(nombreArch);
        	BufferedReader bufferedFileReader=new BufferedReader(fileReader);
        	//Lee los nombres de las variables
        	String nombres=new String();
        	nombres=bufferedFileReader.readLine();
        	cargarTokens(Variables, nombres);
        	for(int i=0; i<Variables.size(); i++)
        	    Padres.addElement(new Vector());
        	//Lee la info del archivo
//        	String s=new String();
        	boolean seguir=true;
           	while(seguir){
            	 String t=bufferedFileReader.readLine();
                 if(t==null)
                    seguir=false;
                 else{
                        Vector v=new Vector();
                        cargarTokens(v, t);
                        Datos.addElement(v);
                 }
           	};
		nroCasos=Datos.size();
           	cargarEstados();
        }catch(IOException e){
	  System.out.println("Error leyendo archivo");
//	  System.exit(0);
	  };
  }

  /**
  *Crea la red bayesiana en base a la estructura de padres
  */
  protected RedBayes crearRedBayesiana(String nombreRed){
        RedBayes rb=null;
        rb=new RedBayes(nombreRed);
        //Agrega variables
        for(int i=0; i < Variables.size(); i++){
            rb.addNodo((String)Variables.get(i));
        }
        //Agrega Arcos
        for(int j=0; j < Padres.size(); j++){
            String nombreVariable=(String)Variables.get(j);
            Vector p=padres(j);
            for(int k=0; k<p.size(); k++){
                String nombrePadre=(String)Variables.get(((Integer)p.get(k)).intValue());
                rb.addArco(nombrePadre, nombreVariable);
            }
        }
        for(int j=0; j < Variables.size(); j++){
            String nombreVariable=(String)Variables.get(j);
            rb.getNodo(nombreVariable).setEstados((Vector)estados.get(j));
        }
        return rb;
  }

  /**
  *Verifica si hay algun camino de origen a destino en el grafo
  */
  protected boolean existeCamino(int origen, int destino) {
        if(origen==destino)
            return true;
		Vector pad=padres(destino);
        boolean encontrado=false;
        for(Enumeration e=pad.elements(); e.hasMoreElements();){
			encontrado=existeCamino(origen, ((Integer)e.nextElement()).intValue());
            if(encontrado)
                  return true;
        }
        return false;
  }

    /**
     * Metodo abstracto para aprender la estructura de una red bayesiana en base a un archivo
     * @param nombreArchivo nombre del archivo origen
     */
    public abstract RedBayes aprenderEstructura(String nombreArchivo);

    protected Vector Variables;
    protected Vector Padres;
    protected Vector estados;
    protected Vector Datos;
    protected int nroCasos;
}
